/*
 * @Author: xiaosihan 
 * @Date: 2023-01-05 17:06:23 
 * @Last Modified by: xiaosihan
 * @Last Modified time: 2024-10-05 09:28:20
 */

import { DesignHistoryData } from "#/type";
import Dexie, { Table } from "dexie";
import { get, isArray, isEmpty, isObject, merge } from "lodash";
import { autorun, observable } from "mobx";

// 设计数据库
class DesignDataBD extends Dexie {
    constructor(dbName: string) {
        super(dbName)
    }
    designDataTable!: Table;
}

// 设计数据的历史记录管理对象
class DesignDataHistory {

    constructor() {
        // 当鼠标抬起时 记录一次历史记录
        document.removeEventListener("mouseup", this.recordHistory);
        document.addEventListener("mouseup", this.recordHistory);

        document.removeEventListener("keyup", this.recordHistory);
        document.addEventListener("keyup", this.recordHistory);

    }

    // 历史记录的状态
    store = observable({

        // 当前设计数据的id
        designDataId: '',
        setId(designDataId: string = "") {
            this.designDataId = designDataId;
        },

        currentDate: Infinity,
        setCurrentDate(currentDate: number) {
            this.currentDate = currentDate;
        },

        // 上一步的数量
        undoNum: 0,
        setUndoNum(undoNum: number) {
            this.undoNum = undoNum;
        },

        // 下一步的数量
        redoNum: 0,
        setRedoNum(redoNum: number) {
            this.redoNum = redoNum;
        }

    });

    //监听设计数据的id发生改变时
    dispose = autorun(async () => {
        const { designDataId } = this.store;
        await new Promise(resolve => requestAnimationFrame(resolve));
        if (designDataId) {
            // 清空临时存储的数据
            this.setStashData();

            const lastHistoryDate = await this.getLatestHistoryData();
            if (lastHistoryDate) {
                // 设置当前时间
                this.store.setCurrentDate(lastHistoryDate.date);
            }
            // 设置上一步的的数量
            this.store.setUndoNum(await this.getUndoNum());
            // 设置下一步的数量
            this.store.setRedoNum(await this.getRedoNum());
        }
    });

    // 专门存储设计数据的历史记录的数据库
    designDataBD: DesignDataBD = (() => {
        let designDataBD = new DesignDataBD("designDataTable");
        designDataBD.version(1).stores({
            designDataTable: "++id,date,designDataId,diffKey,designData"
        });
        return designDataBD;
    })();


    //当数据发生改变时临时存储数据
    stashData?: any;
    setStashDataIng = false; // 正在设置暂存设计数据
    async setStashData(stashData?: any) {
        if (!isEmpty(stashData)) {
            this.setStashDataIng = true;
            this.stashData = stashData;
        }
    }

    // 是否在记录数据中  记录数据时 时间改变不设置画布的desingDate
    // 没有在记录数据时  就是在undoredo  就需要改变画布数据
    recordHistoryIng = true;

    //上一步
    async undo() {
        // 标记没有在记录数据
        this.recordHistoryIng = false;
        const { currentDate } = this.store;
        const latestData = await this.getLatestHistoryData(currentDate);
        if (latestData) {
            this.store.setCurrentDate(latestData.date);
            // 设置上一步的的数量
            this.store.setUndoNum(await this.getUndoNum());
            // 设置下一步的数量
            this.store.setRedoNum(await this.getRedoNum());
        }
    }

    //下一步
    async redo() {
        // 标记正在修改历史记录
        this.recordHistoryIng = false;
        const { currentDate } = this.store;
        let fondResult = await this.designDataBD.designDataTable
            .filter(designData => (designData.designDataId === this.store.designDataId) && (designData.date > currentDate))
            .limit(1)
            .toArray();
        if (fondResult[0]) {
            this.store.setCurrentDate(fondResult[0].date);
            // 设置上一步的的数量
            this.store.setUndoNum(await this.getUndoNum());
            // 设置下一步的数量
            this.store.setRedoNum(await this.getRedoNum());
        }

    }

    // 清除redo
    async clearRedo() {
        const { currentDate } = this.store;
        await this.designDataBD.designDataTable
            .filter(designData => (designData.designDataId === this.store.designDataId) && (designData.date > currentDate))
            .delete()
        // 设置下一步的数量
        this.store.setRedoNum(await this.getRedoNum());
    }

    // 清除所有历史记录
    async clear() {
        await this.designDataBD.designDataTable
            .filter(designData => (designData.designDataId === this.store.designDataId))
            .delete()
    }

    // 当鼠标抬起时记录一次历史记录
    recordHistory = async () => {

        // 标记正在记录数据
        this.recordHistoryIng = true;

        if (!this.stashData) {
            return;
        }

        await new Promise(resolve => setTimeout(resolve, 100));
        while (this.setStashDataIng) {
            this.setStashDataIng = false;
            await new Promise(resolve => setTimeout(resolve, 100));
        }

        const { designDataId } = this.store;

        if (!designDataId) {
            return;
        }

        // 最后一条历史数据
        const currentTrayData = await this.getHistoryDesignDataByCurrentDate();

        // 数据比对
        const diffKey = this.diffDesignData(get(currentTrayData, ['designData']) || {}, this.stashData);

        // 数据有差异时才 保存一条数据
        if (diffKey) {

            // 记录历史数据前 先删除 redo
            await this.clearRedo();

            const date = new Date().valueOf();

            //添加历史记录
            await this.designDataBD.designDataTable
                .add({ date, designDataId, diffKey, designData: this.stashData });

            // 清空临时存储的数据
            this.setStashData();

            // 设置当前时间
            this.store.setCurrentDate(date);

            // 设置上一步的的数量
            this.store.setUndoNum(await this.getUndoNum());

            // 设置下一步的数量
            this.store.setRedoNum(await this.getRedoNum());

        }
    }

    // 获取上一步的数量
    async getUndoNum() {
        const { designDataId, currentDate } = this.store;

        let undoNum = await this.designDataBD.designDataTable
            .filter(designData => (designData.designDataId === designDataId) && (designData.date < currentDate))
            .count()
        return undoNum;
    }

    // 获取下一步的数量
    async getRedoNum() {
        const { designDataId, currentDate } = this.store;

        let redoNum = await this.designDataBD.designDataTable
            .filter(designData => (designData.designDataId === designDataId) && (designData.date > currentDate))
            .count()
        return redoNum;
    }

    // 获取历史记录列表
    async get() {
        let fondResult = await this.designDataBD.designDataTable
            .filter(designData => (designData.designDataId === this.store.designDataId))
            .toArray();
        return fondResult;
    }

    // 设计数据的比对 找出差异的key值
    diffDesignData(designData1: { [key: string]: any } = {}, designData2: { [key: string]: any } = {}) {

        const mergeData = merge({}, designData1, designData2);

        const diffKey: Array<string> = [];

        for (let i in mergeData) {
            if ((isObject(mergeData[i])) || (isArray(mergeData[i]))) {
              if ((isObject(mergeData[i])) && (isArray(mergeData[i]))) {
                const diffkey = this.diffDesignData(designData1[i], designData2[i]);
                if (diffkey) {
                  diffKey.push(`${i}.${diffkey}`);
                }
              }else{
                diffKey.push(i);
              }
            } else if (designData1 && designData2 && designData1[i] !== designData2[i]) {
                diffKey.push(i);
            }
        }

        if (diffKey.length) {
            return diffKey;
        } else {
            return undefined;
        }

    }

    //获取当前选中的历史数据
    async getHistoryDesignDataByCurrentDate(): Promise<DesignHistoryData | undefined> {
        const { currentDate } = this.store;
        let fondResult = await this.designDataBD.designDataTable
            .filter(designData => (designData.designDataId === this.store.designDataId) && (designData.date === currentDate))
            .limit(1)
            .toArray();

        return fondResult[0];
    }

    // 获取最近的一条历史数据
    async getLatestHistoryData(date: number = new Date().valueOf()) {
        let fondResult = await this.designDataBD.designDataTable
            .filter(designData => (designData.designDataId === this.store.designDataId) && (designData.date < date))
            .reverse()
            .limit(1)
            .toArray();
        return fondResult[0];
    }

    // 更具设计数据id 获取全量历史记录  最新的数据在最后面
    async getHistoryData() {
        let fondResult = await this.designDataBD.designDataTable
            .filter(designData => (designData.designDataId === this.store.designDataId))
            .reverse()
            .limit(1)
            .toArray();

        return fondResult[0];
    }

    // 更具 id 和 date 获取单条设计数据
    async getDesignDataByIdAndDate(id: string, date: number): Promise<DesignHistoryData | undefined> {
        let fondResult = await this.designDataBD.designDataTable
            .filter(designData => (designData.designDataId === id) && (designData.date === date))
            .limit(1)
            .toArray();

        return fondResult[0];
    }



}

const designDataHistory = window.designDataHistory = new DesignDataHistory();

export default designDataHistory;
